iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0
自我挑戰組

IT工具與自我學IT的過程分享系列 第 22

Day 2|第一次上手:刷韌體、跑 CameraWebServer

  • 分享至 

  • xImage
  •  

Day 2|第一次上手:刷韌體、跑 CameraWebServer

目標:30–45 分鐘把 ESP32-CAM 跑起來,畫面穩、不卡、還能「一鍵拍照」。
風格:像朋友在旁邊指路+給你一堆現成範例。
本篇可直接貼到部落格(純 Markdown),圖表用 ASCII 呈現,平台相容。


0) TL;DR(今天會做到)

  • 刷好 CameraWebServer ➜ 手機/電腦能看到串流
  • 一鍵 /capture 存圖、/stream 串流
  • 會調整 解析度/幀率/延遲(不卡關的關鍵)
  • 附三個「今天就能玩」的情境範例(含程式碼)

A. 刷機要點(硬體接線+ Arduino 設定)

A-1 接線表(刷機模式)

USB-TTL ESP32-CAM 小提醒
5V 5V 優先穩定供電(5V/≥1A)
GND GND 共地,線不要太細
TX U0R 交叉連線
RX U0T 交叉連線
IO0 GND 只在「刷機」時接上

刷完後:拔掉 IO0→GND按 RST,回一般模式。

A-2 Arduino IDE(精簡設定)

  • 套件:esp32 by Espressif Systems
  • 板子:AI Thinker ESP32-CAM
  • Partition:Huge APPDefault
  • PSRAM:Enabled(超重要)
  • 範例:File → Examples → ESP32 → Camera → CameraWebServer
  • 填入 Wi-Fi SSID/密碼,上傳成功後,序列埠會印出一個網址(如 http://192.168.1.123

B. CameraWebServer「控制面板」怎麼用?

常見端點(不同版本可能略差):

Path 功能
/ 瀏覽器控制台(切解析度、開關閃光燈等)
/stream MJPEG 串流
/capture 拍一張 JPG(按一下就存圖)

一個人的「小直播台」

(你) ──打開瀏覽器──> http://<ESP32-IP>/
                   └─點「Start Stream」→ 影像即時出現

C. 不卡的三把鑰匙:解析度、幀率、網路

C-1 「解析度 vs. 端到端延遲」(概念)

解析度            延遲(越少越順)
QVGA  (320x240)   ■■■□□□□  ≈120ms
VGA   (640x480)   ■■■■□□  ≈200ms
SVGA  (800x600)   ■■■■■□  ≈320ms
XGA  (1024x768)   ■■■■■■  ≈480ms
建議:先用 QVGA / VGA 把網路與畫面調穩,再往上拉。

C-2 網路與電源的黃金法則

  • 串流卡?先靠近 AP、換 20MHz 設定、或直接拉有線 AP。
  • 初始化失敗?80% 是供電不足,換 5V/1–2A、短線材。
  • SD 卡存圖常出錯?FAT32 格式化、換張 A1/A2 等級的卡。

D. 三個「今天就上線」的實例

D-1 一鍵拍照 API(Arduino,GET /shot 直接回傳 JPEG)

#include <WiFi.h>
#include <WebServer.h>
#include "esp_camera.h"
WebServer srv(80);

void handleShot(){
  camera_fb_t * fb = esp_camera_fb_get();
  if(!fb){ srv.send(500,"text/plain","fail"); return; }
  srv.sendHeader("Content-Type","image/jpeg");
  srv.send_P(200,"image/jpeg",(const char*)fb->buf, fb->len);
  esp_camera_fb_return(fb);
}

void setup(){
  // 初始化 Wi-Fi + camera_config_t(略)
  srv.on("/shot", handleShot);
  srv.begin();
}
void loop(){ srv.handleClient(); }

好用情境

IFTTT/Webhook/排程 → GET http://<ESP32-IP>/shot → 得到一張新照片!

D-2 timelapse(縮時攝影,存 SD,每 5 分鐘一張)

#include "esp_camera.h"
#include "FS.h"
#include "SD_MMC.h"

void setup(){
  // ... init camera_config_t ...
  SD_MMC.begin("/sdcard", true); // 1-bit 模式較穩
}

void loop(){
  camera_fb_t *fb = esp_camera_fb_get();
  if(!fb) return;
  String path = "/" + String(millis()) + ".jpg";
  File f = SD_MMC.open(path, FILE_WRITE);
  if(f){ f.write(fb->buf, fb->len); f.close(); }
  esp_camera_fb_return(fb);
  delay(5 * 60 * 1000);  // 5 分鐘
}

產生縮時影片(在電腦或 Pi 上)

ffmpeg -framerate 12 -pattern_type glob -i "*.jpg" -vf "scale=1280:-1" timelapse.mp4

D-3 門鈴自拍(按鈕觸發拍照+閃光燈)

#include "esp_camera.h"
#define BUTTON  12     // 依實際接線
#define LED_PIN 4      // 一些板子把閃光燈接在 GPIO 4
void setup(){
  // init camera...
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
}

void loop(){
  if(digitalRead(BUTTON)==LOW){
    digitalWrite(LED_PIN, HIGH); delay(60); // 補光一下
    camera_fb_t *fb = esp_camera_fb_get();
    // TODO: 存到 SD 或送到你的 /upload API
    esp_camera_fb_return(fb);
    digitalWrite(LED_PIN, LOW);
    delay(800); // 簡單防彈跳
  }
}

客製玩法

  • 拍完把檔案 POST 到你的伺服器 /upload,做雲端相簿。
  • 加一顆蜂鳴器「咔嚓」,儀式感+10。

E. 「看起來更順」的調教術(小撇步)

  • sensor_t * s = esp_camera_sensor_get(); 調畫質:
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_VGA);   // QVGA/VGA/SVGA/XGA...
s->set_brightness(s, 1);              // -2..2
s->set_contrast(s, 1);                // -2..2
s->set_saturation(s, 0);              // -2..2
  • 降延遲小訣竅
    1. 先降解析度到 QVGA/VGA。
    2. 關掉臉部偵測/多餘後處理。
    3. AP 靠近、或用「有線 AP」。
    4. 場景太暗就加補光(LED),畫面壓縮比較穩。

F. 「我卡住了!」— 排障地圖

[無法上傳草稿?] → (IO0 沒接 GND?) → 接上 → 成功
                  └─(TX/RX 反了?) → 交叉接法: TX→U0R, RX→U0T

[Camera init failed?] → (供電不足?) → 換 5V/≥1A & 短線
                       └─(PSRAM 沒開?) → Arduino 設定啟用 PSRAM

[看不到IP?] → (Wi-Fi 密碼/SSID 錯?) → 重寫 → 序列埠複製 IP
            └─(訊號弱?) → 靠近 AP / 改用 20MHz / 有線 AP

[串流很卡?] → 降解析度→關多餘後處理→靠近 AP→再逐步拉高

G. 迷你觀測站(快速檢查)

Python 在 PC/Pi 端觀測 FPS(也能當 demo)

import cv2, time
cap = cv2.VideoCapture("http://<ESP32-IP>/stream")
t, n = time.time(), 0
while True:
    ok, frame = cap.read()
    if not ok: break
    n += 1
    if time.time() - t >= 2:
        print("FPS ≈", n/2)
        n, t = 0, time.time()
    cv2.imshow("ESP32-CAM", frame)
    if cv2.waitKey(1)==27: break

簡易「帶寬估算」(概念)

解析度   平均JPEG大小  10fps 帶寬估
QVGA     ~25KB        ~2.0 Mbps
VGA      ~45KB        ~3.6 Mbps
SVGA     ~70KB        ~5.6 Mbps
(實際依畫面複雜度/壓縮而變動)

H. 今日任務清單 ✅

  • [ ] 刷好 CameraWebServer,瀏覽器能看到串流
  • [ ] GET /capture 成功拿到一張 JPG
  • [ ] 選一個解析度,讓畫面「連續 2 分鐘不卡」
  • [ ] 寫好 /shot APItimelapse 其中一個
  • [ ] 記下「自己的穩定設定」(解析度、補光、AP 位置)

I. 明天預告(Day 3)

  • 把相機變「會工作的相機」:SD timelapse 強化、快速排程、最佳化低延遲、以及「拍到人就通知」的準備功夫(Day 4 會加上 HTTP/MQTT/LINE 完整自動化)。

上一篇
Day 1|銅板價玩影像 AI:ESP32-CAM 一週實作指南
系列文
IT工具與自我學IT的過程分享22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言